#include <string>
#include <iostream>

using namespace std;

class Student {
public:
    // 无参构造函数
    // 初始化列表只能写在构造函数里面
    explicit Student() {
        cout << "调用了 Student 无参的构造函数" << endl;
    }

    // 有参构造函数
    // 初始化列表中和委托构造函数只能二选一
    explicit Student(int uuid, int age) : Student() {
        cout << "调用了 Student 有参的构造函数" << endl;
    }

    // 有参构造函数
    // explicit 关键字可以避免构造函数的隐式转换
    // explicit 只能放到构造函数前面
    explicit Student(int uuid, int age, string name) : uuid(uuid), age(age), name(std::move(name)) {
        cout << "调用了 Student 有参的构造函数" << endl;
    }

    // 析构函数
    // virtual 关键字可以避免使用多态时, 只析构了基类而没有析构派生类
    virtual ~Student() {
        cout << "调用了 Student 的析构函数" << endl;
    };

    // 拷贝函数
    // C++ 默认的拷贝函数是浅拷贝
    Student(const Student &student) {
        cout << "调用了 Student 的拷贝函数" << endl;
    }

public:
    int uuid = 10001;

    int age = 19;

    string name = "Blue";

public:
    void printfStudent() {
        cout << "uuid = " << uuid << endl;
        cout << "age = " << age << endl;
        cout << "name = " << name << endl << endl;
    }
};

void test01() {
    // 调用了 Student 的无参构造函数
    Student student_1;

    // 调用了 Student 的有参构造函数
    Student student_2(10003, 20, "Yui");

    // 调用了 Student 的拷贝函数
    Student student_3(student_1);

    // 调用了 Student 的拷贝函数
    Student student_4 = student_2;

    student_1.printfStudent();
    student_2.printfStudent();
    student_3.printfStudent();
    student_4.printfStudent();
}

void test02() {
    cout << endl;

    // 匿名对象的生命周期在当前行
    Student();

    cout << "test02() 函数结束" << endl << endl;
}

class Teacher {
public:
    // 构造函数
    Teacher() {
        cout << "调用了 Teacher 的构造函数" << endl;
    }

    // 析构函数
    virtual ~Teacher() {
        cout << "调用了 Teacher 的析构函数" << endl;
    }

    // 拷贝函数
    Teacher(const Teacher &teacher) {
        cout << "调用了 Teacher 的拷贝函数" << endl;
    }

public:
    Student student;
};

void test03() {
    // 1.如果类有成员对象, 在创建对象时会先调用成员对象的构造函数, 在调用自身的构造函数
    // 析构函数的调用顺序则反过来
    // 2.成员对象的构造函数调用顺序和定义顺序一样
    // 3.如果类有成员对象, 必须保证成员对象的构造函和析构函数能被调用
    Teacher teacher;
}

int main() {
    test01();

    test02();

    test03();
}